/*
 * LCD_1602_4WIRE.c
 *
 *  Created on: May 3, 2014
 *      Author: Iceworld
 */


#include"LCD_1602_4wire.h"
#include "system.h"

void LcdWrite(alt_u8 data,alt_u8 RS)
{
	//set LCD_DATA on write state
	IOWR_ALTERA_AVALON_PIO_DIRECTION(LCD_DATA_BASE, 0xff);
	//set 1 to LCD_RS for writing data,0 for writing command
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, RS);
	//set 0 to LCD_RW for writing pattern
	//IOWR_ALTERA_AVALON_PIO_DATA(LCD_RW_BASE, WRITE);
	//write data
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data >> 4);
	//set LCD_E
	usleep(1);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x01);
	//clear LCD_E
	usleep(3);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);
	//usleep(1000);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
	//set LCD_E
	usleep(1);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x01);
	//clear LCD_E
	usleep(3);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);
}

void LcdWriteCmd(alt_u8 command)
{
	LcdCheckBusy();
	LcdWrite(command,CMD);
}

void LcdWriteData(alt_u8 data)
{
	LcdCheckBusy();
	LcdWrite(data,DATA);
}

alt_u8 LcdRead(alt_u8 RS)
{
	alt_u8 read_data;
	//set LCD_DATA on read state
	IOWR_ALTERA_AVALON_PIO_DIRECTION(LCD_DATA_BASE, 0x00);
	//set 1 to LCD_RS for reading data,0 for reading command
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, RS);
	//set 1 to LCD_RW for reading pattern
	//IOWR_ALTERA_AVALON_PIO_DATA(LCD_RW_BASE, READ);
	//set LCD_E
	usleep(1);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x01);
	//read data
	usleep(1);
	read_data = IORD_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE);
	//clear LCD_E
	usleep(2);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);
	usleep(1);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x01);
	read_data = read_data << 4;
	//read data
	usleep(1);
	read_data |= IORD_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE);
	//clear LCD_E
	usleep(2);
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);

	return read_data;
}

alt_u8 LcdReadCmd()
{
	alt_u8 read_cmd;
	LcdCheckBusy();
	read_cmd = LcdRead(CMD);
	return read_cmd;
}

alt_u8 LcdReadData()
{
	alt_u8 read_data;
	LcdCheckBusy();
	read_data = LcdRead(DATA);
	return read_data;
}

void LcdCheckBusy()
{
	//while(LcdRead(CMD) & 0x80);
	usleep(1200);
}

void LcdClearScreen()
{
	LcdWriteCmd(0x01);
}
void InitLcd()
{
	//clear the LCD_E
	IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);
	usleep(200000);
	//write third time 0x38 to LCD 1602,do not check busy,third time to ensure initial succeed
	LcdWrite(0x28,CMD);
	usleep(5000);
	LcdWrite(0x28,CMD);
	usleep(5000);
	LcdWrite(0x28,CMD);
	usleep(5000);
	//write 0x28 once more,set display mode(16*2,5*7,4bit)
	LcdWriteCmd(0x28);
	//close screen
	LcdWriteCmd(0x08);
	//clear screen
	LcdWriteCmd(0x01);
	//set cursor mode(N=1)
	LcdWriteCmd(0x06);
	//open the screen
	LcdWriteCmd(0x0c);
}

void LocateXY(alt_u8 x,alt_u8 y)
{
	x &= 0x0f;					//ensure the x between 0 and 31
	y &= 0x01;					//ensure that the y is 1 or 0
	if(y)
	{
		LcdCheckBusy();
		LcdWriteCmd(x | 0x40 | 0x80);
	}
	else
	{
		LcdCheckBusy();
		LcdWriteCmd(x | 0x80);
	}
}

void PutChar(char value,alt_u8 x,alt_u8 y)
{
	LocateXY(x,y);
	LcdWriteData(value);
}

alt_u8 PutStr(char *value,alt_u8 x,alt_u8 y)
{
	alt_u8 len = 0,i;
	while(value[len] > 31) len ++;
	for(i = 0;i < len;i ++)
	{
		PutChar(value[i],x ++,y);
		if(x == 16)				//Cyclic display
		{
			x = 0;
			y ^= 0x01;
		}
	}
	return len;					//return the length of the string
}
